<html>
<head><meta charset="utf-8"><title>Empty alloc as data of dyn function fat pointer? · t-compiler/help · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/index.html">t-compiler/help</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Empty.20alloc.20as.20data.20of.20dyn.20function.20fat.20pointer.3F.html">Empty alloc as data of dyn function fat pointer?</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="245242884"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Empty%20alloc%20as%20data%20of%20dyn%20function%20fat%20pointer%3F/near/245242884" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alexa VanHattum <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Empty.20alloc.20as.20data.20of.20dyn.20function.20fat.20pointer.3F.html#245242884">(Jul 07 2021 at 21:13)</a>:</h4>
<p>I'm trying to understand the LLVM IR that Rustc generates for the following code with a dynamic trait function pointer:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">takes_dyn_fun</span><span class="p">(</span><span class="n">param_fun</span>: <span class="kp">&amp;</span><span class="nc">dyn</span><span class="w"> </span><span class="nb">Fn</span><span class="p">()</span><span class="w"> </span>-&gt; <span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">param_fun</span><span class="p">();</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">unit_fun</span><span class="p">()</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">takes_dyn_fun</span><span class="p">(</span><span class="o">&amp;</span><span class="n">unit_fun</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>If I unpack the fat pointer generated for <code>param_fun</code>, the vtable indicates a data size of 0. In the <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=80ab157a7da36e6178fc2094332b74c6">generated LLVM IR</a>, the first half of the fat pointer is set to a constant <code>@alloc1</code>, which appears to be a size 0, zeroinitialized constant. This pointer is passed to the generated calls to <code>Fn::call</code>; but ignored (except for debugging?) in favor of <code>Fn::call</code> calling the  <code>unit_fun</code> function directly:</p>
<div class="codehilite" data-code-language="LLVM"><pre><span></span><code><span class="k">define</span> <span class="k">internal</span> <span class="k">void</span> <span class="vg">@_ZN4core3ops8function2Fn4call17h9afee5aa38cd1564E</span><span class="p">({}*</span> <span class="k">nonnull</span> <span class="k">align</span> <span class="m">1</span> <span class="nv">%_1</span><span class="p">)</span> <span class="k">unnamed_addr</span> <span class="vg">#2</span> <span class="nv">!dbg</span> <span class="nv nv-Anonymous">!94</span> <span class="p">{</span>
<span class="nl">start:</span>
  <span class="nv">%_1.dbg.spill</span> <span class="p">=</span> <span class="k">alloca</span> <span class="p">{}*,</span> <span class="k">align</span> <span class="m">8</span>
  <span class="nv">%_2</span> <span class="p">=</span> <span class="k">alloca</span> <span class="p">{},</span> <span class="k">align</span> <span class="m">1</span>
  <span class="k">store</span> <span class="p">{}*</span> <span class="nv">%_1</span><span class="p">,</span> <span class="p">{}**</span> <span class="nv">%_1.dbg.spill</span><span class="p">,</span> <span class="k">align</span> <span class="m">8</span> <span class="c">; only used for debugging?</span>
  <span class="k">call</span> <span class="k">void</span> <span class="vg">@llvm.dbg.declare</span><span class="p">(</span><span class="k">metadata</span> <span class="p">{}**</span> <span class="nv">%_1.dbg.spill</span><span class="p">,</span> <span class="k">metadata</span> <span class="nv nv-Anonymous">!104</span><span class="p">,</span> <span class="k">metadata</span> <span class="nv">!DIExpression</span><span class="p">()),</span> <span class="nv">!dbg</span> <span class="nv nv-Anonymous">!110</span>
  <span class="k">call</span> <span class="k">void</span> <span class="vg">@llvm.dbg.declare</span><span class="p">(</span><span class="k">metadata</span> <span class="p">{}*</span> <span class="nv">%_2</span><span class="p">,</span> <span class="k">metadata</span> <span class="nv nv-Anonymous">!106</span><span class="p">,</span> <span class="k">metadata</span> <span class="nv">!DIExpression</span><span class="p">()),</span> <span class="nv">!dbg</span> <span class="nv nv-Anonymous">!110</span>
<span class="c">; call playground::unit_fun</span>
  <span class="k">call</span> <span class="k">void</span> <span class="vg">@_ZN10playground8unit_fun17h2223108562f19d24E</span><span class="p">(),</span> <span class="nv">!dbg</span> <span class="nv nv-Anonymous">!110</span> <span class="c">; unit_fun is called directly</span>
</code></pre></div>
<p>This is in the context of the a custom Rust backend in the <a href="https://github.com/model-checking/rmc]">RMC</a>project, where our goal is to have a bit-precise match to rustc. Our backend currently generates invalid code because our generated implementation of <code>Fn::once</code> calls the data argument as if it is the function pointer to <code>unit_fun</code>. I'm not sure if we are missing some monomorphization or similar optimization step there.</p>
<p>So my questions:</p>
<ol>
<li>Why is the purpose of the zeroinitialized <code>@alloc1</code> in the Rustc generated code? </li>
<li>Is calling <code>unit_fun</code> directly from the <code>Fn::call</code> implementation an optimization, and if so, any pointers to where in the source this is defined? Are there any RFCs or issues that describe fat pointer/vtable generation in this case?</li>
</ol>
<p>Thanks so much!</p>



<a name="245243719"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Empty%20alloc%20as%20data%20of%20dyn%20function%20fat%20pointer%3F/near/245243719" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Empty.20alloc.20as.20data.20of.20dyn.20function.20fat.20pointer.3F.html#245243719">(Jul 07 2021 at 21:20)</a>:</h4>
<ol>
<li><code>Fn::call</code> takes an <code>&amp;self</code> param. Even if <code>Self</code> is a ZST, you still need a pointer.</li>
<li>No, that is the definition of the closure shim for functions. It is defined in the shim generation code in compiler/rustc_mir_built.</li>
</ol>



<a name="245244047"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Empty%20alloc%20as%20data%20of%20dyn%20function%20fat%20pointer%3F/near/245244047" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Empty.20alloc.20as.20data.20of.20dyn.20function.20fat.20pointer.3F.html#245244047">(Jul 07 2021 at 21:23)</a>:</h4>
<p>Vtable generation doesn't happen any differently for this than for real closures or user defined types. It just takes function pointers to all methods of the trait implementation, size, align and drop_in_place and puts them in the vtable. It doesn't matter that the implementation is "faked" by other parts of the compiler. The vtable generation sees a "real" implementation.</p>



<a name="245317692"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/182449-t-compiler/help/topic/Empty%20alloc%20as%20data%20of%20dyn%20function%20fat%20pointer%3F/near/245317692" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alexa VanHattum <a href="https://rust-lang.github.io/zulip_archive/stream/182449-t-compiler/help/topic/Empty.20alloc.20as.20data.20of.20dyn.20function.20fat.20pointer.3F.html#245317692">(Jul 08 2021 at 14:06)</a>:</h4>
<p>Thank you, that's really helpful!</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>